package com.feeyo.groundservice.http.core

import android.net.ParseException
import com.feeyo.groundservice.http.base.BusinessExceptionHandler
import com.feeyo.groundservice.http.beans.BusinessBaseResponse
import com.feeyo.groundservice.http.constant.BUSINESS_CODE_EXCEPTION
import com.feeyo.groundservice.http.constant.UNKNOWN_CODE_ERROR
import com.feeyo.groundservice.http.exception.BusinessException
import com.feeyo.groundservice.http.exception.ExceptShow.onShowException
import com.feeyo.groundservice.http.exception.ExceptionErrorCode
import com.feeyo.groundservice.http.exception.ExceptionErrorCode.DATA_NULL_CODE
import com.feeyo.groundservice.http.exception.ExceptionErrorCode.UNKNOWN_CODE
import com.feeyo.groundservice.http.exception.ExceptionReason
import com.feeyo.groundservice.http.exception.ServerResponseException
import com.feeyo.groundservice.http.utils.MoshiUtils
import com.squareup.moshi.JsonDataException
import okhttp3.Request
import okio.Timeout
import org.json.JSONException
import retrofit2.Call
import retrofit2.Callback
import retrofit2.HttpException
import retrofit2.Response
import java.io.InterruptedIOException
import java.net.ConnectException
import java.net.UnknownHostException


/**
 * 重新定义Call,适配到HttpResult 以及错误转换Handler
 *
 * Call<T> 接口的作用：
 * 这个接口主要的作用就是发送一个HTTP请求，Retrofit默认的实现是OkHttpCall<T>，你可以根据实际情况实现你自己的Call类
 * 这里定义HttpResultCall是为了
 * @param S
 * @property call
 * @property businessExceptionHandler
 */
internal class HttpResponseCall<S : Any>(
    private val call: Call<S>,
    private val businessExceptionHandler: BusinessExceptionHandler?,
    private val allowDataIsNull: Boolean,
    private val businessBaseResponse: Class<BusinessBaseResponse>

) : Call<HttpResult<S>> {


    /**
     * 异步发送请求并通知调用回调返回的 response body或者 错误信息
     *
     *  callback.onResponse(Call<T> call, Response<T> response);
     *  callback.onResponse(this@HttpResponseCall,Response.success(HttpResult.Success(body)))
     *
     *
     *  callback.onResponse(this@HttpResponseCall,Response.success([yourCustomResponse]))
     *  差异在 [yourCustomResponse] 这里都用Response.success 了
     *
     * @param callback Http 请求的回调方法  ，其中<HttpResult<S>> Successful response body type.
     */
    override fun enqueue(callback: Callback<HttpResult<S>>) {
        return call.enqueue(object : Callback<S> {

            override fun onResponse(call: Call<S>, response: Response<S>) {
                val data = response.body()//如果结构适配了，则返回data部分，否则就是全部数据（code+msg+data）
                val code = response.code()//Http请求的状态码，如200
                val error = response.errorBody()

                //Http 返回[200..300).
                if (response.isSuccessful) {//响应成功

                    if (data != null) {//整个返回非空
                        callback.onResponse(
                            this@HttpResponseCall,
                            Response.success(HttpResult.Success(data))
                        )
                    } else {
                        // the body is null，这也是一种异常错误。会有吗
//                        callback.onResponse(
//                            this@HttpResponseCall,
//                            Response.success(HttpResult.UnknownError(null))
//                        )
                        if (allowDataIsNull) {
                            callback.onResponse(
                                this@HttpResponseCall,
                                Response.success(HttpResult.Success(null))
                            )
                        } else {
                            callback.onResponse(
                                this@HttpResponseCall,
                                Response.success(
                                    HttpResult.Failure(
                                        "response body is null,please check your setting.",
                                        DATA_NULL_CODE
                                    )
                                )
                            )
                        }
                    }
                } else {
                    //这是[4xx, 5xx] 的错误信息，这种也是Http 有返回比较具体的错误 （如果是异常就是直接onFailed了））
                    if (error != null && error.contentLength() > 0) {
                        //有明确的返回错误
                        // 500X
                        val errorResponse =
                            MoshiUtils.fromJson(error.string(), businessBaseResponse)

                        businessExceptionHandler?.onFailure(
                            BusinessException(
                                errorResponse?.code ?: UNKNOWN_CODE,
                                errorResponse?.message ?: UNKNOWN_CODE_ERROR
                            )
                        )

                        callback.onResponse(
                            this@HttpResponseCall,
                            Response.success(
                                HttpResult.Failure(
                                    errorResponse?.message ?: UNKNOWN_CODE_ERROR,
                                    errorResponse?.code ?: UNKNOWN_CODE
                                )
                            )
                        )
                    } else {//没有Error Body 的情况
                        callback.onResponse(
                            this@HttpResponseCall,
                            Response.success(
                                HttpResult.Failure(
                                    error?.string() ?: "message field is empty.", code
                                )
                            )
                        )

                    }
                }
            }

            /**
             * 失败，还有各种Exception
             *
             * [-200,-100] 业务方不要占用了，作为预留全局公共错误码
             */
            override fun onFailure(call: Call<S>, throwable: Throwable) {
                val message = throwable.message
                val networkResponse = when (throwable) {
                    //这个是Moshi 解析 code ！= OK-Code 的时候抛出的异常错误，业务服务器会给出详细的错误
                    //强烈建议业务服务器给的错误编码不要和传统的Http 请求的code 有重合，负数最好
                    //尽量拓展完整一点,所有的业务异常状态应该抛给全局的异常处理
                    is BusinessException -> {
                        businessExceptionHandler?.onFailure(throwable) //抛出给全局错误处理
                        onShowException(ExceptionReason.BUSINESS_EXCEPTION,message)
                        val msg = if (message.isNullOrEmpty())
                            BUSINESS_CODE_EXCEPTION
                        else
                            message

                        HttpResult.Failure(msg, throwable.code)
                    }

                    //Json 解析错误
                    is JsonDataException, is JSONException, is ParseException -> {
                        onShowException(ExceptionReason.PARSE_ERROR)
                        HttpResult.Failure(
                            message = message ?: "Json Parse Exception",
                            code = ExceptionErrorCode.PARSE_ERROR_CODE
                        )
                    }

                    //HTTP错误
                    is HttpException -> {
                        onShowException(ExceptionReason.BAD_NETWORK)
                        HttpResult.Failure(
                            message = message ?: "Http Exception",
                            code = ExceptionErrorCode.BAD_NETWORK_CODE
                        )
                    }

                    //连接错误 IO的
                    is ConnectException, is UnknownHostException -> {
                        onShowException(ExceptionReason.CONNECT_ERROR)
                        HttpResult.Failure(
                            message = message ?: "Http Link Exception",
                            code = ExceptionErrorCode.CONNECT_ERROR_CODE
                        )
                    }

                    //连接超时 IO的
                    is InterruptedIOException -> {
                        onShowException(ExceptionReason.CONNECT_TIMEOUT)
                        HttpResult.Failure(
                            message = message ?: "Connect Timeout Exception",
                            code = ExceptionErrorCode.CONNECT_TIMEOUT_CODE
                        )
                    }

                    //服务器返回的异常
                    is ServerResponseException -> {
                        onShowException(ExceptionReason.SERVER_RESPONSE_ERROR)
                        HttpResult.Failure(
                            message = message ?: "Server Response Exception",
                            code = ExceptionErrorCode.SERVER_RESPONSE_CODE
                        )
                    }

                    //其他未知错误
                    else -> {
                        onShowException(ExceptionReason.UNKNOWN_ERROR)
                        HttpResult.Failure(
                            message ?: "UnKnow Error Exception",
                            ExceptionErrorCode.UNKNOWN_ERROR_CODE
                        )

                    }

                }

                callback.onResponse(this@HttpResponseCall, Response.success(networkResponse))
            }
        })
    }

    /**
     * 暂时不支持吧，拦截处理Token 过期不是很有用吗？
     *
     * @return
     */
    override fun execute(): Response<HttpResult<S>> {
        throw UnsupportedOperationException("HttpResponseCall doesn't support execute")
    }

    override fun isExecuted() = call.isExecuted

    override fun clone() = HttpResponseCall(
        call.clone(),
        businessExceptionHandler,
        allowDataIsNull,
        businessBaseResponse
    )

    override fun isCanceled() = call.isCanceled

    override fun cancel() = call.cancel()

    override fun request(): Request = call.request()

    override fun timeout(): Timeout = call.timeout()


}
